/**
 * Classe contenant des fonctions utiles
 * 
 * @author Marie-Hélène Goddet, Damien Finck, Cédric Schaller
 * 
 */
package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Vector;

import javax.swing.JPanel;
import javax.swing.text.BadLocationException;

import utils.Debug;
import utils.Resources;
import fastwriting.Choix;
import fastwriting.Config;
import fastwriting.FastWriting;

public class Fonctions {
	/**
	 * Dessine le point.
	 * @param g le graphics où dessiner le point
	 * @param c la couleur à utiliser
	 * @param p les coordonnées du point à afficher
	 */
	public static void dessinerPoint(Graphics g,Color c,Point p) {
		g.setColor(c);
		g.fillOval(p.x,p.y,4,4);
	}
	/**
	 * Dessine une ligne
	 * @param g le graphics où dessiner la ligne
	 * @param c la couleur à utiliser
	 * @param begin le point du début de la ligne
	 * @param end le point de fin de la ligne
	 */
	public static void dessinerLigne(Graphics g,Point begin,Point end) {
		
		g.setColor(Config.stringToColor(FastWriting.config.get("Personnalisation").get("CouleurTrait").toString()));
		
		if (begin.x!=-1 && begin.y!=-1)
		{
			//Je dessine un trait entre chaque point de chaque évènement
			g.drawLine(begin.x, begin.y, end.x, end.y);
			
			if (!FastWriting.config.get("Personnalisation").get("TailleTrait").toString().equals("fin")) {
				/* Je grossit chaque droite avec 4 autres droites */
				g.drawLine(begin.x+1, begin.y, end.x+1, end.y);
				g.drawLine(begin.x-1, begin.y, end.x-1, end.y);
				g.drawLine(begin.x, begin.y+1, end.x, end.y+1);
				g.drawLine(begin.x, begin.y-1, end.x, end.y-1);
			}
			if (FastWriting.config.get("Personnalisation").get("TailleTrait").toString().equals("épais")) {
				/* Je grossit chaque droite avec 4 autres droites */
				g.drawLine(begin.x+2, begin.y, end.x+2, end.y);
				g.drawLine(begin.x-2, begin.y, end.x-2, end.y);
				g.drawLine(begin.x, begin.y+2, end.x, end.y+2);
				g.drawLine(begin.x, begin.y-2, end.x, end.y-2);
			}
		}
	}
	/**
	 * Retourne les coordonnées du point de l'évenement par rapport à l'IHM
	 * si l'évement se passe sur une touche
	 * @param ihm ihm
	 * @param arg0 l'evenement 
	 * @param jt la touche liée à l'évenement
	 * @return les coordonnées du point
	 */
	public static Point getPoint_relativeToIHM(IHM ihm,MouseEvent arg0,JTouche jt) {
		Point p;
		Insets i = ihm.getInsets();
		
		// ihm <---> JClavier
		int jc_x=ihm.jclavier.getLocation().x+i.left;
		int jc_y=ihm.jclavier.getLocation().y+i.top;
		// JClavier <---> JTouche
		int touche_x=jt.getParent().getLocation().x+jt.getLocation().x;
		int touche_y=jt.getParent().getLocation().y+jt.getLocation().y;
		//Touche <---> Event Interne Touche
		int event_x=arg0.getX();
		int event_y=arg0.getY();

		p = new Point(jc_x+touche_x+event_x,jc_y+touche_y+event_y);
		
		return p;
	}
	/**
	 * Retourne les coordonnées du point de l'évenement par rapport à l'IHM
	 * si l'évement se passe sur un Jpanel
	 * @param ihm ihm
	 * @param arg0 l'evenement 
	 * @param jp le panel liée à l'évenement
	 * @return les coordonnées du point
	 */
	public static Point getPoint_relativeToIHM(IHM ihm,MouseEvent arg0,JPanel jp) {
		Point p;
		Insets i = ihm.getInsets();
		
		int jp_x=ihm.jgeneral.getLocation().x+i.left;
		int jp_y=ihm.jgeneral.getLocation().y+i.top;
		int event_x=arg0.getX();
		int event_y=arg0.getY();
		
		p = new Point(jp_x+event_x,jp_y+event_y);
		return p;
	}
	/**
	 * Retourne les coordonnées de la touche par rapport à l'IHM
	 * @param ihm ihm
	 * @param jt la touche 
	 * @return les coordonnées du point
	 */
	public static Point getPoint_relativeToIHM(IHM ihm,JTouche jt) {
		Point p;
		Insets i = ihm.getInsets();
		
		// ihm <---> JClavier
		int jc_x=ihm.jclavier.getLocation().x+i.left;
		int jc_y=ihm.jclavier.getLocation().y+i.top;
		// JClavier <---> JTouche
		int touche_x=jt.getParent().getLocation().x+jt.getLocation().x;
		int touche_y=jt.getParent().getLocation().y+jt.getLocation().y;
		
		p = new Point(jc_x+touche_x,jc_y+touche_y);
		return p;
	}
	/**
	 * Efface la liste des choix
	 * @param ihm ihm
	 */
	public static void clear_liste_choix(IHM ihm) {
		for (int i=0;i<JScreen.NB_CHOIX;i++) {
			ihm.jscreen.jl_choix[i].setText(null);
			ihm.jscreen.jl_choix[i].setToolTipText(null);
		}
	}
	/**
	 * Calcule un nombre representant le changement de direction ou pas sur une touche
	 * et affecte à la touche
	 * @param c1 le point 1
	 * @param c2 le point 2
	 * @param c3 le point 3
	 * @param c4 le point 4
	 */
	public static void changeDirection(Point c1,Point c2,Point c3,Point c4) {
		// Algorithme de changement de direction sur une touche
		
		if (c1.x!=-1 && c1.y!=-1 && c2.x!=-1 && c2.y!=-1) { // J'ai 3 points (2 sur Exited et 1 sur Entered)
			double x1,x2,x3,x4,y1,y2,y3,y4;
			x1=c1.x;x2=c2.x;x3=c3.x;x4=c4.x;
			y1=c1.y;y2=c2.y;y3=c3.y;y4=c4.y;
			double a1=0;
			double a2=0;
			boolean angledroit=false;
			boolean demitour=false;
			if (c1.equals(c2) || c3.equals(c4)) {
				Debug.addLog("Trop vite", Debug.LOG_WARNING, "changeDirection");
			} else {
				if ((x1==x2 || x3==x4 )&& (y1==y2 || y3==y4)) {
					angledroit=true;
				}else {
					if (Math.abs(x1-x2)<=2 && Math.abs(x4-x3)<=2 ){
						Debug.addLog("On echange", Debug.LOG_WARNING, "changeDirection");
						a1=(x2-x1)/(y2-y1);
						a2=(x4-x3)/(y4-y3);
						demitour = (y1-y2)*(y3-y4)<0;
					} else {
						a1=(y2-y1)/(x2-x1);
						a2=(y4-y3)/(x4-x3);
						demitour = (x1-x2)*(x3-x4)<0;
					}
				}
				double theta;
				if (angledroit) {
					theta = Math.PI/2;
				} else {
					theta = (Math.atan(a1) - Math.atan(a2));
				}
				//Debug.addLog("E ("+x1+";"+y1+")("+x2+";"+y2+")("+x3+";"+y3+")("+x4+";"+y4+") ["+a1+";"+a2+"]  {"+theta+"}", Debug.LOG_INFO, "changeDirection");
				Debug.addLog("angle : "+theta, Debug.LOG_INFO, "changeDirection");

				if (demitour){
					theta = 2 - Math.abs(Math.sin(theta));
				} else {
					theta = Math.abs(Math.sin(theta));
				}

				Debug.addLog(FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).getCar()+" : "+theta/2,Debug.LOG_INFO,"changeDirection");

				FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setChangementDirection(theta/2);
			}
			//Debug.addLog("Exited", Debug.LOG_INFO, "changeDirection");
		}
	}
	/**
	 * Affiche les propositions en dessous de l'écran
	 * @param bestWord le meilleur mot
	 * @param ihm l'ihm
	 * @param choice la classe calculant les propositions
	 */
	public static void affichage_proposition(IHM ihm,Choix choice,boolean isBest) {
		int[] ordre = {3,4,2,5,1,6,0}; // ordre d'affichage des mots optimisé
		Color[] c_ordre = {Color.BLACK,new Color(20,20,20),new Color(40,40,40),new Color(60,60,60),new Color(80,80,80),new Color(100,100,100),new Color(120,120,120)};
		
		double nbCar=0;
		
		List<String> l;
		if (isBest) l = choice.get7NextBest();
		else l = choice.get7NextOther();
		
		for (int i=0;i<l.size();i++) {
			nbCar+=l.get(i).length();
			ihm.jscreen.jl_choix[ordre[i]].setText(l.get(i));
			ihm.jscreen.jl_choix[ordre[i]].setToolTipText(l.get(i));
			ihm.jscreen.jl_choix[ordre[i]].setForeground(c_ordre[i]);
		}
		
		ihm.jscreen.jb_left.setEnabled(false);
		ihm.jscreen.jb_left.setIcon(Resources.getImageIcon("images/left_gris.png", Evenements.class));
		ihm.jscreen.jb_right.setEnabled(false);
		ihm.jscreen.jb_right.setIcon(Resources.getImageIcon("images/right_gris.png", Evenements.class));
		if (isBest) {
			if (l.size()==JScreen.NB_CHOIX) {
				ihm.jscreen.jb_right.setEnabled(true);
				ihm.jscreen.jb_right.setIcon(Resources.getImageIcon("images/right_vert.png", Evenements.class));
			}
		} else {
			ihm.jscreen.jb_left.setEnabled(true);
			ihm.jscreen.jb_left.setIcon(Resources.getImageIcon("images/left_vert.png", Evenements.class));
			
		}
		double width=ihm.jscreen.jp_propositions.getSize().width;
		for (int i=0;i<l.size();i++) {
			int nbPix=(int)(width*(double)ihm.jscreen.jl_choix[ordre[i]].getText().length()/nbCar);
			ihm.jscreen.jl_choix[ordre[i]].setVisible(true);
			ihm.jscreen.jl_choix[ordre[i]].setPreferredSize(new Dimension(nbPix-5,20));
		}
	}
	/**
	 * Supprime la liste des propositions
	 * @param ihm l'ihm
	 */
	public static void clear_propositions(IHM ihm) {
		ihm.jscreen.jb_right.setEnabled(false);
		ihm.jscreen.jb_right.setIcon(Resources.getImageIcon("images/right_gris.png", Evenements.class));
		ihm.jscreen.jb_left.setEnabled(false);
		ihm.jscreen.jb_left.setIcon(Resources.getImageIcon("images/left_gris.png", Evenements.class));
		for (int i=0;i<JScreen.NB_CHOIX;i++) {
			ihm.jscreen.jl_choix[i].setVisible(false);
			ihm.jscreen.jl_choix[i].setText("");
			ihm.jscreen.jl_choix[i].setToolTipText("");
		}
	}
	public static void swype_letter(IHM ihm,JTouche jt_survol,Point crt) {
		if (FastWriting.wordWriting.size()==0) {
			//ajout du caractère
			FastWriting.wordWriting.add(jt_survol.getText().charAt(0));
			// algo de centre de la touche
			Point t = Fonctions.getPoint_relativeToIHM(ihm,jt_survol);
			t.x=crt.x-t.x;
			t.y=crt.y-t.y;
			double centerLetter=Math.sqrt( Math.pow(t.x-JClavier.TOUCHES_STANDARD.width/2, 2) + Math.pow(t.y-JClavier.TOUCHES_STANDARD.height/2, 2) );//Pythagore
			FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setCentreTouche(centerLetter);
		} else if (jt_survol.getText().charAt(0)!=FastWriting.wordWriting.lastCar()) {
			//ajout du caractère
			FastWriting.wordWriting.add(jt_survol.getText().charAt(0));
			// algo de centre de la touche
			Point t = Fonctions.getPoint_relativeToIHM(ihm,jt_survol);
			t.x=crt.x-t.x;
			t.y=crt.y-t.y;
			double centerLetter=Math.sqrt( Math.pow(t.x-JClavier.TOUCHES_STANDARD.width/2, 2) + Math.pow(t.y-JClavier.TOUCHES_STANDARD.height/2, 2) );//Pythagore
			FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setCentreTouche(centerLetter);
		} else {
			//ajout du timer sur cette touche
			FastWriting.wordWriting.addTimeLast();
			// algo de centre de la touche
			double old=FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).getCentreTouche();
			Point t = Fonctions.getPoint_relativeToIHM(ihm,jt_survol);
			t.x=crt.x-t.x;
			t.y=crt.y-t.y;
			double centerLetter=Math.sqrt( Math.pow(t.x-JClavier.TOUCHES_STANDARD.width/2, 2) + Math.pow(t.y-JClavier.TOUCHES_STANDARD.height/2, 2) );//Pythagore
			if (centerLetter<old) {
				FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setCentreTouche(centerLetter);
				Debug.addLog("("+t.x+";"+t.y+")  "+FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).getCar()+"   "+centerLetter, Debug.LOG_INFO, "centreTouche");
			}
		}
	}
	public static void algo_boucle(IHM ihm,Point crt,Vector<Point> v,int cpt) {
		Insets i = ihm.getInsets();
		Point pos_ecran_1 = new Point(ihm.jscreen.getLocation().x+i.left,ihm.jscreen.getLocation().y+i.top);
		Point pos_ecran_2 = new Point(pos_ecran_1.x+ihm.jscreen.getSize().width,pos_ecran_1.y+ihm.jscreen.getSize().height);
		if (pos_ecran_1.x<=crt.x && pos_ecran_2.x>=crt.x && pos_ecran_1.y<=crt.y && pos_ecran_2.y>=crt.y) {
			if (!ihm.jclavier.jt_maj.isLock() && cpt==0) {
				Graphics g = ihm.getGraphics();
				if (v.size()<3 || !findSimilarCroisement(crt.x,crt.y,v)) {//il faut 3 pts minimun pour start l'algo +(x4,y4) pas encore dans le vecteur v
					v.add(new Point(crt.x,crt.y));
					g.setColor(Color.BLUE);
				} else {
					g.setColor(Color.BLACK);
					Debug.addLog("  *** BOUCLE !!!! ***", Debug.LOG_WARNING, "boucleEcran");
					FastWriting.wordWriting.setAllInMaj();
					
					ihm.jclavier.jt_maj.setLock(true);
					ihm.jclavier.jt_maj.setEnfonce(true);
					ActionEvent e = new ActionEvent(ihm.jclavier.jt_maj,1001,"JClavier_LOCK_MAJ");
					ihm.jclavier.jt_maj.getActionListener().actionPerformed(e);
				}
				//g.fillOval(crt.x,crt.y,4,4);
			}
			cpt++;
			if (cpt>=4) cpt=0;//1 pts sur 4 d'affiché
		}
	}
	public static void algo_boucle(IHM ihm,Point crt,Vector<Point> v,int cpt,MouseEvent arg0,JTouche jt) {
		Point pos_ecran_1 = Fonctions.getPoint_relativeToIHM(ihm,arg0,jt);
		pos_ecran_1.x-=arg0.getX();
		pos_ecran_1.y-=arg0.getY();
		Point pos_ecran_2 = new Point(pos_ecran_1.x+jt.getSize().width,pos_ecran_1.y+jt.getSize().height);
		
		if (pos_ecran_1.x<=crt.x && pos_ecran_2.x>=crt.x && pos_ecran_1.y<=crt.y && pos_ecran_2.y>=crt.y) {
			if (!ihm.jclavier.jt_maj.isLock() && cpt==0) {
				Graphics g = ihm.getGraphics();
				if (v.size()<3 || !findSimilarCroisement(crt.x,crt.y,v)) {//il faut 3 pts minimun pour start l'algo +(x4,y4) pas encore dans le vecteur v
					v.add(new Point(crt.x,crt.y));
					g.setColor(Color.BLUE);
				} else {
					g.setColor(Color.BLACK);
					Debug.addLog("  *** BOUCLE !!!! ***", Debug.LOG_WARNING, "boucleEcran");
					v.clear();cpt=0;
					if (jt.getMode()==JTouche.TOUCHE_STANDARD) {
						FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setCentreTouche(0);
						FastWriting.wordWriting.add(jt.getText().charAt(0));
						FastWriting.wordWriting.getLettre(FastWriting.wordWriting.size()-1).setCentreTouche(0);
					} else if (jt==ihm.jclavier.jt_backspace) {
						String texte = ihm.jscreen.jta_ecran.getText();
						int tmp1,tmp2,tmp3;
						
						tmp1 = texte.substring(0,ihm.jscreen.jta_ecran.getCaretPosition()).lastIndexOf(' ');
						tmp2 = texte.substring(0,ihm.jscreen.jta_ecran.getCaretPosition()).lastIndexOf('\n');
						tmp3 = texte.substring(0,ihm.jscreen.jta_ecran.getCaretPosition()).lastIndexOf('.');
						
						int debutMot = Math.max(tmp1,Math.max(tmp2,tmp3));
						
						tmp1 = texte.indexOf(' ',ihm.jscreen.jta_ecran.getCaretPosition());
						tmp2 = texte.indexOf('\n',ihm.jscreen.jta_ecran.getCaretPosition());
						tmp3 = texte.indexOf('.',ihm.jscreen.jta_ecran.getCaretPosition());
						
						tmp1=(tmp1==-1)?ihm.jscreen.jta_ecran.getDocument().getLength():tmp1;
						tmp2=(tmp2==-1)?ihm.jscreen.jta_ecran.getDocument().getLength():tmp2;
						tmp3=(tmp3==-1)?ihm.jscreen.jta_ecran.getDocument().getLength():tmp3;
						
						int finMot= Math.min(tmp1,Math.min(tmp2,tmp3));
						
						finMot = (finMot == -1)?ihm.jscreen.jta_ecran.getDocument().getLength():finMot; //plus d'espaces, la fin est a la fin du texte
						
						ihm.jscreen.jta_ecran.setSelectionStart(debutMot+1);
						ihm.jscreen.jta_ecran.setSelectionEnd(finMot);
						
						int start,end;
						start = ihm.jscreen.jta_ecran.getSelectionStart();
						end = ihm.jscreen.jta_ecran.getSelectionEnd();
						end = (end == ihm.jscreen.jta_ecran.getDocument().getLength())?end:end+1; //Supprime l espace si on est pas a la fin
						try {
							ihm.jscreen.jta_ecran.getDocument().remove(start, end-start);
						} catch (BadLocationException e) {
							e.printStackTrace();
						}
					}
				}
				//g.fillOval(crt.x,crt.y,4,4);
			}
			cpt++;
			if (cpt>=4) cpt=0;//1 pts sur 4 d'affiché
		}
	}
	public static boolean findSimilarCroisement(int x4,int y4,Vector<Point> v) {
		boolean res=false;
		double x1,x2,x3,y1,y2,y3;
		double aA,aB,bA,bB;
		
		x3=v.get(v.size()-1).x;//(x4;y4) n'est pas encore dans le vecteur
		y3=v.get(v.size()-1).y;//donc les derniers sont (x3;y3)
		
		double f;
		for (int i=0;i<(v.size()-5);i++) {//un croisement ne peut pas être sur un nombre inférieur a 3
			x1=v.get(i).x;
			y1=v.get(i).y;
			x2=v.get(i+1).x;
			y2=v.get(i+1).y;
			
			if (x1==x2 || x3==x4)
				Debug.addLog("x1==x2 : ***WARNING***", Debug.LOG_WARNING, "boucleEcran");
			if (x1==x2) x1+=0.0000001;
			if (x3==x4) x3+=0.0000001;
			if (x1==x2 || x3==x4)
				Debug.addLog("x1==x2 : ***ERREUR*** plantage de l'algo de boucle", Debug.LOG_ERREUR, "boucleEcran");
			
			aA=(y2-y1)/(x2-x1);
			bA=y1-aA*x1;
			
			aB=(y4-y3)/(x4-x3);
			bB=y3-aB*x3;
			
			f=(bB-bA)/(aA-aB);
			if ( f>=Math.min(x1,x2) && f<=Math.max(x1,x2) && f>=Math.min(x3,x4) && f<=Math.max(x3,x4) ) {
				res=true;
			}
			Debug.addLog("("+x1+";"+y1+")-("+x2+";"+y2+") {"+aA+","+bA+"}/"+f+"/{"+aB+","+bB+"} ("+x3+";"+y3+")-("+x4+";"+y4+")", Debug.LOG_INFO, "boucleEcran");
					
		}
		Debug.addLog("------------------------------------------------------------", Debug.LOG_INFO, "boucleEcran");
		return res;
	}

}
